using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using ADModify.Library;
using System.Xml;
using System.IO;

namespace ADModify.NET.GUI
{
	/// <summary>
	/// Summary description for Undo.
	/// </summary>
	public class frmUndo : System.Windows.Forms.Form
	{
		private System.Windows.Forms.TextBox txtUndoFilePath;
		private System.Windows.Forms.Button btnUndoButton;
		private System.Windows.Forms.Label label1;
		private System.Windows.Forms.PictureBox pictureBox3;
		private System.Windows.Forms.Button btnUndoUndo;
		private System.Windows.Forms.Button btnUndoCancel;
		private System.Windows.Forms.ProgressBar progressBarUndo;
		private System.Windows.Forms.TextBox txtUndoServerPath;
		private System.Windows.Forms.Label label2;
		private System.Windows.Forms.PictureBox pictureBox1;
		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		public frmUndo()
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();

			//
			// TODO: Add any constructor code after InitializeComponent call
			//
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(frmUndo));
			this.txtUndoFilePath = new System.Windows.Forms.TextBox();
			this.btnUndoButton = new System.Windows.Forms.Button();
			this.label1 = new System.Windows.Forms.Label();
			this.pictureBox3 = new System.Windows.Forms.PictureBox();
			this.btnUndoUndo = new System.Windows.Forms.Button();
			this.btnUndoCancel = new System.Windows.Forms.Button();
			this.progressBarUndo = new System.Windows.Forms.ProgressBar();
			this.txtUndoServerPath = new System.Windows.Forms.TextBox();
			this.label2 = new System.Windows.Forms.Label();
			this.pictureBox1 = new System.Windows.Forms.PictureBox();
			this.SuspendLayout();
			// 
			// txtUndoFilePath
			// 
			this.txtUndoFilePath.Location = new System.Drawing.Point(16, 48);
			this.txtUndoFilePath.Name = "txtUndoFilePath";
			this.txtUndoFilePath.Size = new System.Drawing.Size(296, 20);
			this.txtUndoFilePath.TabIndex = 0;
			this.txtUndoFilePath.Text = "";
			// 
			// btnUndoButton
			// 
			this.btnUndoButton.Location = new System.Drawing.Point(328, 48);
			this.btnUndoButton.Name = "btnUndoButton";
			this.btnUndoButton.TabIndex = 1;
			this.btnUndoButton.Text = "Browse";
			this.btnUndoButton.Click += new System.EventHandler(this.button1_Click);
			// 
			// label1
			// 
			this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.label1.Location = new System.Drawing.Point(16, 24);
			this.label1.Name = "label1";
			this.label1.Size = new System.Drawing.Size(376, 24);
			this.label1.TabIndex = 2;
			this.label1.Text = "Select the xml file that contains the changes you wish to undo:";
			// 
			// pictureBox3
			// 
			this.pictureBox3.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox3.Image")));
			this.pictureBox3.Location = new System.Drawing.Point(16, 88);
			this.pictureBox3.Name = "pictureBox3";
			this.pictureBox3.Size = new System.Drawing.Size(384, 8);
			this.pictureBox3.TabIndex = 26;
			this.pictureBox3.TabStop = false;
			// 
			// btnUndoUndo
			// 
			this.btnUndoUndo.Location = new System.Drawing.Point(104, 184);
			this.btnUndoUndo.Name = "btnUndoUndo";
			this.btnUndoUndo.Size = new System.Drawing.Size(104, 23);
			this.btnUndoUndo.TabIndex = 27;
			this.btnUndoUndo.Text = "Undo";
			this.btnUndoUndo.Click += new System.EventHandler(this.btnUndoUndo_Click);
			// 
			// btnUndoCancel
			// 
			this.btnUndoCancel.Location = new System.Drawing.Point(208, 184);
			this.btnUndoCancel.Name = "btnUndoCancel";
			this.btnUndoCancel.Size = new System.Drawing.Size(104, 23);
			this.btnUndoCancel.TabIndex = 28;
			this.btnUndoCancel.Text = "Cancel";
			this.btnUndoCancel.Click += new System.EventHandler(this.btnUndoCancel_Click);
			// 
			// progressBarUndo
			// 
			this.progressBarUndo.Location = new System.Drawing.Point(16, 216);
			this.progressBarUndo.Name = "progressBarUndo";
			this.progressBarUndo.Size = new System.Drawing.Size(384, 23);
			this.progressBarUndo.TabIndex = 29;
			// 
			// txtUndoServerPath
			// 
			this.txtUndoServerPath.Location = new System.Drawing.Point(16, 130);
			this.txtUndoServerPath.Name = "txtUndoServerPath";
			this.txtUndoServerPath.Size = new System.Drawing.Size(384, 20);
			this.txtUndoServerPath.TabIndex = 35;
			this.txtUndoServerPath.Text = "";
			// 
			// label2
			// 
			this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.label2.Location = new System.Drawing.Point(16, 106);
			this.label2.Name = "label2";
			this.label2.Size = new System.Drawing.Size(376, 24);
			this.label2.TabIndex = 34;
			this.label2.Text = "Type the FQDN of the DC to perform changes against (optional):";
			// 
			// pictureBox1
			// 
			this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image")));
			this.pictureBox1.Location = new System.Drawing.Point(16, 170);
			this.pictureBox1.Name = "pictureBox1";
			this.pictureBox1.Size = new System.Drawing.Size(384, 8);
			this.pictureBox1.TabIndex = 33;
			this.pictureBox1.TabStop = false;
			// 
			// frmUndo
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(416, 245);
			this.Controls.Add(this.txtUndoServerPath);
			this.Controls.Add(this.label2);
			this.Controls.Add(this.pictureBox1);
			this.Controls.Add(this.progressBarUndo);
			this.Controls.Add(this.btnUndoCancel);
			this.Controls.Add(this.btnUndoUndo);
			this.Controls.Add(this.pictureBox3);
			this.Controls.Add(this.label1);
			this.Controls.Add(this.btnUndoButton);
			this.Controls.Add(this.txtUndoFilePath);
			this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
			this.Name = "frmUndo";
			this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
			this.Text = "ADModify.NET";
			this.Closing += new System.ComponentModel.CancelEventHandler(this.frmUndo_Closing);
			this.ResumeLayout(false);

		}
		#endregion

		private void frmUndo_Closing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			Application.Exit();
		}

		private void button1_Click(object sender, System.EventArgs e)
		{
			OpenFileDialog fdlg = new OpenFileDialog(); 
			fdlg.InitialDirectory = @"c:\" ; 
			fdlg.Filter = "XML Files (*.xml)|*.xml";
			fdlg.FilterIndex = 2 ; 
			fdlg.RestoreDirectory = true ; 
			if(fdlg.ShowDialog() == DialogResult.OK) 
			{ 
				txtUndoFilePath.Text = fdlg.FileName ; 
			} 
		}

		private void btnUndoCancel_Click(object sender, System.EventArgs e)
		{
			Application.Exit();
		}

		private string UndoChanges(string logFileName, string ServerName)
		{


			Undo myUndo = new Undo();

			StreamWriter sw;
			string UserDN = null;
			string attribute = null;
			string type = null;
			string oldValue = null; 
			string newValue = null;
			int userCount = 0;
			int CurrentUserCount = 0;  //used to track the # of the current user
			int skippedUserCount = 0;
			

			//Initialize the xml log file
			LogFile xmllog = new LogFile();
			
			//initialize the undo log file
			if(!File.Exists("Undo.log"))	//undo log doesn't exist, create it
			{
				sw = File.CreateText("Undo.log");
			}
			else
			{
				sw = File.AppendText("Undo.log");
			}
			
			sw.WriteLine("");
			sw.WriteLine("-------------------------------------------");
			sw.WriteLine("ADModify Undo Log - " + System.DateTime.Now);
			sw.WriteLine("-------------------------------------------");
			sw.WriteLine("");

			LogFile log = new LogFile();

	
			//first loop through the file to get our user count since XmlTextReader doesn't contain a method to count the # of users.
			XmlTextReader counter = new XmlTextReader(logFileName);
			while(counter.Read())
			{
				
				if(counter.NodeType == XmlNodeType.Element)
				{
					if(counter.Name=="user")
					{
						userCount++;
					}
				}
			}
			counter.Close();

			string RawDateTime = System.DateTime.Now.ToString();
			RawDateTime = RawDateTime.Replace(" ","").Replace("/","").Replace(":","");
			string logFileName1 = RawDateTime + ".xml";
			XmlTextWriter logWriter = new XmlTextWriter(logFileName1, null);

			
			logWriter.WriteStartDocument(false);
			logWriter.WriteDocType("LogFile", null, null, null);
			logWriter.WriteStartElement("XmlRoot", logFileName);

			DateTime startTime = System.DateTime.Now;


			//progress bar
			progressBarUndo.Minimum=0;
			progressBarUndo.Maximum=userCount;
			progressBarUndo.Step=1;

			XmlTextReader reader = new XmlTextReader(logFileName);
			
			while(reader.Read())
			{
				
				if (reader.NodeType == XmlNodeType.Element) 
				{
					if(reader.Name=="user")
					{

						//increment the progress bar
						progressBarUndo.PerformStep();

						CurrentUserCount++;

						UserDN = reader.GetAttribute("UserDN");
						attribute = reader.GetAttribute("attribute");
						type = reader.GetAttribute("type");
						oldValue = reader.GetAttribute("oldValue");
						newValue = reader.GetAttribute("newValue");

						//do not proceed if any of the values are missing
						if(UserDN!=null && attribute!=null && type!=null && oldValue!=null && newValue!=null)
						{
							//filter out changes that cannot be undone
							if(attribute=="Import Mailbox Rights")
							{
								skippedUserCount++;
								sw.WriteLine("User " + UserDN + " was skipped because the undo of importing mailbox rights");
								sw.WriteLine("is not supported.");
							}
							if(attribute=="killmail (remove exchange attributes)")
							{
								skippedUserCount++;
								sw.WriteLine("User " + UserDN + " was skipped because the creating of Exchange attributes cannot");
								sw.WriteLine("be done using ADModify.  Please use the AD Users and Computers snapin to mailbox");
								sw.WriteLine("enable the object instead.");
							}
							else if(oldValue.EndsWith("is not a supported attribute and therefore changes to it cannot be undone."))
							{
								skippedUserCount++;
								sw.WriteLine("User " + UserDN + " was skipped because the previous attribute modification was unsupported");
								sw.WriteLine("and cannot be undone.");
							}
							else if(attribute=="Set msExchMailboxSecurityDescriptor")
							{
								skippedUserCount++;
								sw.WriteLine("User " + UserDN + " was skipped because the setting of Mailbox Rights cannot be");
								sw.WriteLine("undone.  In order to clear this attribute, you must run admodify in custom mode and");
								sw.WriteLine("clear the msExchMailboxSecurityDescriptor attribute.");
							}
							else if(type=="Success")	//we can only undo a modification that originally worked (skip logged failures)
							{
							
								myUndo.UndoChanges(logWriter, UserDN, attribute, oldValue, newValue, ServerName);
								sw.WriteLine("An undo request was processed for user " + UserDN);
								sw.WriteLine("Please check " + logFileName + " for more information.");
								sw.WriteLine("");
							}
							else	//Failure was originally Logged, skipping this user
							{
								skippedUserCount++;
								sw.WriteLine("");
								sw.WriteLine("User " + UserDN + " was skipped because the log file indicates that the last change attempt");
								sw.WriteLine("was marked as " + type);
								sw.WriteLine("");
								
							}
						}
						else	//one of the above was null, skip the user and write to undo.log
						{
							switch(type)
							{
								case "Failure":
								{
									skippedUserCount++;
									sw.WriteLine("");
									sw.WriteLine("User " + UserDN + " was skipped because the log file indicates that the last change attempt");
									sw.WriteLine("was marked as " + type);
									sw.WriteLine("");
									break;
								}
								case "Already Set to Specified Value": 
								{
									skippedUserCount++;
									sw.WriteLine("");
									sw.WriteLine("User " + UserDN + " was skipped because the log file indicates that the last change attempt");
									sw.WriteLine("was marked as " + type);
									sw.WriteLine("");
									break;
								}
								default: 
								{
									skippedUserCount++;
									sw.WriteLine("");
									sw.WriteLine("An error occured while parsing the XML file, one or more attributes were missing a value.");
									sw.WriteLine("The following attributes have these values:");
									sw.WriteLine("UserDN: " + UserDN);
									sw.WriteLine("attribute: " + attribute);
									sw.WriteLine("type: " + type);
									sw.WriteLine("oldValue: " + oldValue);
									sw.WriteLine("newValue: " + newValue);
									sw.WriteLine("");
									break;
								}
							}
						}

					}
				}
			}

			

//			//print results in the undo.log file
			string Results = xmllog.ReturnResults();
			string[] ResultsArray = Results.Split(',');
			sw.WriteLine("");
			sw.WriteLine("Skipped Users: {0}", skippedUserCount);
			sw.WriteLine("Successful changes: {0}", ResultsArray[0]);
			sw.WriteLine("Already set to specified value: {0}", ResultsArray[1]);
			sw.WriteLine("Failed changes: {0}", ResultsArray[2]);
			sw.WriteLine("");

			//close out the log files
			sw.Close();
			logWriter.Flush();
			logWriter.Close();

			Results=Results+","+skippedUserCount+","+startTime;	//append skipped so we can return to the calling function
			return Results;

		}
		private void btnUndoUndo_Click(object sender, System.EventArgs e)
		{

			if(txtUndoFilePath.Text.Length==0)
			{
				MessageBox.Show("Please Select a Log File.");
				return;
			}
			Cursor.Current = Cursors.WaitCursor;

			Undo myUndo = new Undo();
			LogFile log = new LogFile();

			//timer
			DateTime endTime;
			TimeSpan finalCount;

			string RawDateTime = System.DateTime.Now.ToString();
			RawDateTime = RawDateTime.Replace(" ","").Replace("/","").Replace(":","");
			string logFileName = RawDateTime + ".xml";


			//start the undo process
			string UndoResults = UndoChanges(txtUndoFilePath.Text, txtUndoServerPath.Text);
			if(UndoResults==null)
			{
				return;
			}

			Cursor.Current = Cursors.Arrow;

			endTime = System.DateTime.Now;
			string[] ResultsArray = UndoResults.Split(',');
			finalCount = endTime.Subtract(Convert.ToDateTime(ResultsArray[4]));
			MessageBox.Show("Operation Completed in " + finalCount + " seconds.\n\nSkipped Users: " + ResultsArray[3] + "\nSuccessful changes: " + ResultsArray[0] + "\nAlready set to specified value: " + ResultsArray[1] + "\nFailed changes: " + ResultsArray[2] + "\n\nCheck " + logFileName + " and undo.log for details.");
			Application.Exit();
		}
	}
}
